﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using Moq;

namespace MvcWiki.Test.Service.WikiPageService
{
    public class GetAllWikiPagesFacts
    {
        [Fact]
        public void Call()
        {
            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            IList<MvcWiki.Model.WikiPage> wikiPages = service.GetAllWikiPages("Namespace");
        }

        [Fact]
        public void Calls_Repository()
        {
            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetAllWikiPages("Namespace"));

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.GetAllWikiPages("Namespace");

            wikiPageRepository.VerifyAll();
        }

        [Fact]
        public void Throws_Exception_If_Namespace_Does_Not_Exist()
        {
            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetAllWikiPages("Namespace")).Throws<MvcWiki.Exceptions.NamespaceDoesNotExistException>();

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            Assert.Throws<MvcWiki.Exceptions.NamespaceDoesNotExistException>(
                () => service.GetAllWikiPages("Namespace"));
        }

        [Fact]
        public void Returns_IList_Of_WikiPages()
        {
            var wikiPages = new List<MvcWiki.Model.WikiPage> {
                new MvcWiki.Model.WikiPage(),
                new MvcWiki.Model.WikiPage(),
                new MvcWiki.Model.WikiPage()
            };

            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            wikiPageRepository.Setup(x => x.GetAllWikiPages("Namespace")).Returns(wikiPages);

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            Assert.Equal<IList<MvcWiki.Model.WikiPage>>(wikiPages, service.GetAllWikiPages("Namespace"));
        }

        [Fact]
        public void Calls_WikiUserProvider_CanIndexPages()
        {
            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.GetAllWikiPages("Namespace");

            wikiUserProvider.Verify(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>()));
        }

        [Fact]
        public void Calls_IWikiNamespaceRepository_GetWikiNamespace()
        {
            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.GetAllWikiPages("Namespace");

            wikiNamespaceRepository.Verify(x => x.GetWikiNamespace("Namespace"));
        }

        [Fact]
        public void Calls_WikiUserProvider_CanIndexPages_With_WikiNamespace_From_Repository()
        {
            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();

            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };
            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(true);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            service.GetAllWikiPages("Namespace");

            wikiUserProvider.Verify(x => x.CanIndexPages(wikiNamespace));
        }

        [Fact]
        public void Throws_Exception_If_CanIndexPages_Is_False()
        {
            var wikiPageRepository = new Mock<MvcWiki.Repository.IWikiPageRepository>();
            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiPageRepository()).Returns(wikiPageRepository.Object);
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var wikiUserProvider = new Mock<MvcWiki.User.IWikiUserProvider>();
            wikiUserProvider.Setup(x => x.CanIndexPages(It.IsAny<MvcWiki.Model.WikiNamespace>())).Returns(false);

            var service = new MvcWiki.Service.WikiPageService(repositoryFactory.Object, unitOfWork.Object, wikiUserProvider.Object);

            Assert.Throws<MvcWiki.Exceptions.AuthorizationException>(
                () => service.GetAllWikiPages("Namespace"));
        }
    }
}
